#pragma once
#include <memory>
#include <iostream>
#include "mytcp.hpp"
#include <unistd.h>
#include <sys/epoll.h>
class EpollServer
{
    const static int size = 256;
    const static int event_size = 64;

public:
    EpollServer(int port)
        : _listensockfd(std::make_unique<TcpSocket>()), _isrunning(false), _epfd(-1)
    {
        _listensockfd->BuildListenMethod(port);
        _epfd = epoll_create(size); // 创建一个epoll模型
        if (_epfd == -1)
        {
            // epoll失败
            LOG(LogLevel::FATAL) << "epoll_create error";
            exit(epoll_create_err);
        }
        // 将listen套接字设置进入epoll
        struct epoll_event event;
        event.events = EPOLLIN; // 我们关心listen套接字的读事件
        event.data.fd = _listensockfd->Fd();
        int n = epoll_ctl(_epfd, EPOLL_CTL_ADD, _listensockfd->Fd(), &event);
        if (n == -1)
        {
            // epoll_ctl失败
            LOG(LogLevel::FATAL) << "epoll_ctl error";
            exit(epoll_ctl_err);
        }
    }
    void Accepter()
    {
        Addr client;
        int fd = _listensockfd->Accept(&client);
        if (fd >= 0)
        {
            LOG(LogLevel::DEBUG) << "new link,fd=:" << fd << ",client is" << client.GetAddr();
            // 将该fd放入数组
            struct epoll_event event;
            event.events = EPOLLIN; // 我们关心listen套接字的读事件
            event.data.fd = fd;
            int n = epoll_ctl(_epfd, EPOLL_CTL_ADD, fd, &event);
            if (n == -1)
            {
                // epoll_ctl失败
                LOG(LogLevel::FATAL) << "epoll_ctl error";
                exit(epoll_ctl_err);
            }
            else
            {
                LOG(LogLevel::DEBUG) << "epoll_ctl add success,fd:" << fd;
            }
        }
    }
    void Recver(int sockfd)
    {
        char buffer[1024];
        int n = recv(sockfd, buffer, sizeof(buffer) - 1, 0);
        if (n > 0)
        {
            // 正常读
            buffer[n - 1] = 0;
            LOG(LogLevel::DEBUG) << "client says@" << buffer;
        }
        else if (n == 0)
        {
            // 此时客户端退出
            LOG(LogLevel::DEBUG) << "client quit...";
            // 不关心该fd并且关闭该fd
            int n = epoll_ctl(_epfd, EPOLL_CTL_DEL, sockfd, nullptr);
            if (n == -1)
            {
                LOG(LogLevel::ERROR) << "epoll_ctl remove " << sockfd << " failed";
            }
            close(sockfd);
        }
        else
        {
            // recv韩束出错
            LOG(LogLevel::FATAL) << "recv error...";
            // 不关心该fd并且关闭该fd
            int n = epoll_ctl(_epfd, EPOLL_CTL_DEL, sockfd, nullptr);
            if (n == -1)
            {
                LOG(LogLevel::ERROR) << "epoll_ctl remove " << sockfd << " failed";
            }
            close(sockfd);
        }
    }
    void Dispatcher()
    {
        // std::cout<<"进入dispatcher逻辑块"<<std::endl;
        for (int i = 0; i < event_size; i++)
        {
            int sockfd = _evs[i].data.fd;
            uint32_t event = _evs[i].events;
            if (event & EPOLLIN) // 判断时间是否就绪
            {
                // 该fd存在于数组中
                if (sockfd == _listensockfd->Fd())
                {
                    // 将该fd加入辅助数组中
                    // std::cout<<"找到listenfd,进入accepter逻辑块"<<std::endl;
                    Accepter();
                }
                else
                {
                    // 关心读事件
                    // std::cout<<"进入recver逻辑块"<<std::endl;
                    Recver(sockfd);
                }
            }
            // else
            // {
            //     std::cout<<"不存在_fd_array["<<i<<"]"<<std::endl;
            // }
        }
        // 开始accept
        //  int fd=_listensockfd->Accept();
        //  if(fd>=0)
        //  {
        //      LOG(LogLevel::DEBUG)<<"new link,fd=:"<<fd;
        //  }
    }
    void Start()
    {
        _isrunning = true;
        int timeout = -1;
        while (_isrunning)
        {
            // 在循环中进行epoll_wait
            int n = epoll_wait(_epfd, _evs, event_size, timeout);
            switch (n)
            {
            case 0:
                LOG(LogLevel::INFO) << "overtime wait...";
                break;
            case -1:
                LOG(LogLevel::ERROR) << "wait error...";
                break;
            default:
                Dispatcher();
                break;
            }
        }
        _isrunning = false;
    }
    void Stop()
    {
        _isrunning = false;
    }
    ~EpollServer()
    {
        _listensockfd->Close();
        close(_epfd);
    }

private:
    std::unique_ptr<Socket> _listensockfd;
    bool _isrunning;
    // 因为select之后,原来fd_set中的值就会改变,所以需要一个辅助数组记录
    int _epfd;
    // epoll_wait的数组
    struct epoll_event _evs[event_size];
};